package com.wisdom.benefit.jufa.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;

import com.wisdom.benefit.jufa.R;

import java.util.Objects;

/**
 * 线性布局，支持分隔线，使用Adapter管理
 * Created by zhoudawei on 2016/11/21.
 */

public class DividerLinearLayout extends LinearLayout {

    private Drawable mDrawable;
    private int mDividerWidth;
    private int mDividerHeight;
    private int mDividerMarginStart;
    private int mDividerMarginTop;
    private int mDividerMarginEnd;
    private int mDividerMarginBottom;
    private boolean mUseViewCache;

    private SparseArrayCompat<View> mViewArray = new SparseArrayCompat<>();
    private SparseArrayCompat<Size> mViewSizeArray = new SparseArrayCompat<>();

    private AdapterView.OnItemClickListener mOnItemClickListener;

    private BaseAdapter mAdapter;
    private final DataSetObserver mDataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            reset();
        }

        @Override
        public void onInvalidated() {
            reset();
        }
    };

    public DividerLinearLayout(Context context) {
        this(context, null);
    }

    public DividerLinearLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DividerLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DividerLinearLayout, defStyleAttr, 0);
        mDrawable = array.getDrawable(R.styleable.DividerLinearLayout_divider_res);
        mDividerMarginStart = array.getDimensionPixelSize(R.styleable.DividerLinearLayout_divider_margin_start, 0);
        mDividerMarginTop = array.getDimensionPixelSize(R.styleable.DividerLinearLayout_divider_margin_top, 0);
        mDividerMarginEnd = array.getDimensionPixelSize(R.styleable.DividerLinearLayout_divider_margin_end, 0);
        mDividerMarginBottom = array.getDimensionPixelSize(R.styleable.DividerLinearLayout_divider_margin_bottom, 0);
        mUseViewCache = array.getBoolean(R.styleable.DividerLinearLayout_use_view_cache, true);
        array.recycle();

        if (mDrawable == null) {
            mDividerWidth = 0;
            mDividerHeight = 0;
        } else {
            mDividerWidth = mDrawable.getIntrinsicWidth();
            mDividerHeight = mDrawable.getIntrinsicHeight();
        }

        setWillNotDraw(mDrawable == null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mViewSizeArray.clear();
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            Size size = mViewSizeArray.get(i);
            if (size == null) size = new Size();
            size.setWidth(child.getMeasuredWidth());
            size.setHeight(child.getMeasuredHeight());
            mViewSizeArray.put(i, size);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    Rect rect;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mDrawable == null) return;
        if (getOrientation() == VERTICAL)
            drawDividerVertical(canvas);
        else if (getOrientation() == HORIZONTAL)
            drawDividerHorizontal(canvas);
    }

    private void drawDividerVertical(Canvas canvas) {
        for (int i = 1; i < mViewArray.size(); i++) {
            if (rect == null) rect = new Rect();
            rect.left = getPaddingStart() + mDividerMarginStart;
            rect.right = getWidth() - getPaddingEnd() - mDividerMarginEnd;
            final int height = getHeightSum(i);
            rect.top = height - mDividerMarginBottom - mDividerHeight;
            rect.bottom = height - mDividerMarginBottom;
            mDrawable.setBounds(rect);
            mDrawable.draw(canvas);
        }
    }

    private void drawDividerHorizontal(Canvas canvas) {
        for (int i = 1; i < mViewArray.size(); i++) {
            if (rect == null) rect = new Rect();
            final int width = getWidthSum(i);
            rect.left = width - mDividerMarginEnd - mDividerWidth;
            rect.right = getWidth() - mDividerMarginEnd;
            rect.top = getPaddingTop() + mDividerMarginTop;
            rect.bottom = getHeight() - getPaddingBottom() - mDividerMarginBottom;
            mDrawable.setBounds(rect);
            mDrawable.draw(canvas);
        }
    }

    private int getHeightSum(int sum) {
        int height = getPaddingTop();
        for (int i = 0; i < sum; i++) {
            height += Objects.requireNonNull(mViewSizeArray.get(i)).getHeight() + mDividerMarginTop + mDividerHeight + mDividerMarginBottom;
        }
        return height;
    }

    private int getWidthSum(int sum) {
        int width = getPaddingStart();
        for (int i = 0; i < sum; i++) {
            width += Objects.requireNonNull(mViewSizeArray.get(i)).getWidth() + mDividerMarginStart + mDividerWidth + mDividerMarginEnd;
        }
        return width;
    }

    public void setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    public void setAdapter(@NonNull BaseAdapter adapter) {
        if (mAdapter != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        mAdapter = adapter;
        mAdapter.registerDataSetObserver(mDataSetObserver);
        reset();
    }

    private void reset() {
        initViews();
    }

    private void initViews() {
        if (mAdapter == null) {
            mViewArray.clear();
            removeAllViews();
        } else {
            final int count = getChildCount();
            if (count > mAdapter.getCount()) {//移除多余项
                mViewArray.removeAtRange(mAdapter.getCount(), count - mAdapter.getCount());
                removeViews(mAdapter.getCount(), count - mAdapter.getCount());
            }

            //更新视图
            if (!mUseViewCache) {
                removeAllViews();
                mViewArray.clear();
                mViewSizeArray.clear();
            }
            for (int i = 0; i < mAdapter.getCount(); i++) {
                final View convertView = mViewArray.size() > i ? mViewArray.get(i) : null;
                final View view = mAdapter.getView(i, convertView, this);
                view.setTag(R.id.tag_pos, i);
                view.setOnClickListener(mOnClickListener);
                mViewArray.put(i, view);
                if (view.getParent() == null)
                    addView(view, i);
                LayoutParams lp = (LayoutParams) view.getLayoutParams();
                if (getOrientation() == VERTICAL)
                    lp.topMargin = (i == 0) ? 0 : mDividerMarginTop + mDividerHeight + mDividerMarginBottom;
                else if (getOrientation() == HORIZONTAL)
                    lp.setMarginStart((i == 0) ? 0 : mDividerMarginStart + mDividerWidth + mDividerMarginEnd);
                view.setLayoutParams(lp);
            }
        }
    }

    private OnClickListener mOnClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            Object obj = v.getTag(R.id.tag_pos);
            if (obj == null) return;
            int pos = Integer.valueOf(String.valueOf(obj));
            if (mOnItemClickListener != null)
                mOnItemClickListener.onItemClick(null, v, pos, v.getId());
        }
    };

    private class Size {

        private int width, height;

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        int getHeight() {
            return height;
        }

        void setHeight(int height) {
            this.height = height;
        }
    }
}
